/**
第一节、寻找满足条件的两个数
第14题（数组）：
题目：输入一个数组和一个数字，在数组中查找两个数，使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字，输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15，因此输出4和11。

1.直接穷举，从数组中任意选取两个数，判定它们的和是否为输入的那个数字。此举复杂度为O（N^2）。很显然，我们要寻找效率更高的解法。 
2.题目相当于，对每个a[i]，然后查找判断sum-a[i]是否也在原始序列中，每一次要查找的时间都要花费为O（N），这样下来，最终找到两个数
还是需要O（N^2）的复杂度。那如何提高查找判断的速度列?对了，二分查找，将原来O（N）的查找时间提高到O（logN），这样对于N个a[i]，
都要花logN的时间去查找相对应的sum-a[i]是否在原始序列中，总的时间复杂度已降为O（N*logN），且空间复杂度为O（1）。（如果有序，
直接二分O（N*logN），如果无序，先排序后二分，复杂度同样为O（N*logN+N*logN）=O（N*logN），空间总为O（1））。 
3.可以依据上述思路2的思想，a[i]在序列中，如果a[i]+a[k]=sum的话，那么sum-a[i]（a[k]）也必然在序列中，举个例子，如下：
原始序列：1、 2、 4、 7、11、15 用输入数字15减一下各个数，得到对应的序列为：
对应序列：14、13、11、8、4、 0 
第一个数组以一指针i 从数组最左端开始向右扫描，第二个数组以一指针j 从数组最右端开始向左扫描，如果下面出现了和上面一样的数，
即a[*i]=a[*j]，就找出这俩个数来了。如上，i，j最终在第一个，和第二个序列中找到了相同的数4和11，，所以符合条件的两个数，即为4+11=15。
怎么样，两端同时查找，时间复杂度瞬间缩短到了O（N），但却同时需要O（N）的空间存储第二个数组（@飞羽：要达到O(N)的复杂度，第一个数组
以一指针i 从数组最左端开始向右扫描，第二个数组以一指针j 从数组最右端开始向左扫描，首先初始i指向元素1，j指向元素0，谁指的元素小，
谁先移动，由于1（i）>0（j），所以i不动，j向左移动。然后j移动到元素4发现大于元素1，故而停止移动j，开始移动i，直到i指向4，这时,i指向
的元素与j指向的元素相等，故而判断4是满足条件的第一个数；然后同时移动i,j再进行判断，直到它们到达边界）。 
4.当然，你还可以构造hash表，正如编程之美上的所述，给定一个数字，根据hash映射查找另一个数字是否也在数组中，只需用O（1）的时间，
 这样的话，总体的算法通上述思路3 一样，也能降到O（N），但有个缺陷，就是构造hash额外增加了O（N）的空间，此点同上述思路 3。不过，
 空间换时间，仍不失为在时间要求较严格的情况下的一种好办法。 
5.如果数组是无序的，先排序（n*logn），然后用两个指针i，j，各自指向数组的首尾两端，令i=0，j=n-1，然后i++，j--，逐次判断
a[i]+a[j]?=sum，如果某一刻a[i]+a[j]>sum，则要想办法让sum的值减小，所以此刻i不动，j--，如果某一刻a[i]+a[j]<sum，则要想办法让sum的值
增大，所以此刻i++，j不动。所以，数组无序的时候，时间复杂度最终为O（n*logn+n）=O（n*logn），若原数组是有序的，则不需要事先的排序，
直接O（n）搞定，且空间复杂度还是O（1），此思路是相对于上述所有思路的一种改进。（如果有序，直接两个指针两端扫描，时间O（N），
如果无序，先排序后两端扫描，时间O（N*logN+N）=O（N*logN），空间始终都为O（1））。
（与上述思路2相比，排序后的时间开销由之前的二分的n*logn降到了扫描的O（N））。 
总结：
不论原序列是有序还是无序，解决这类题有以下三种办法：
1、二分（若无序，先排序后二分），时间复杂度总为O（n*logn），空间复杂度为O（1）；
2、扫描一遍X-S[i] 映射到一个数组或构造hash表，时间复杂度为O（n），空间复杂度为O（n）；
3、两个指针两端扫描（若无序，先排序后扫描），时间复杂度最后为：有序O（n），无序O（n*logn+n）=O（n*logn），空间复杂度都为O（1）。 
所以，要想达到时间O（N），空间O（1）的目标，除非原数组是有序的（指针扫描法），不然，当数组无序的话，就只能先排序，后指针扫描法或二分（时间n*logn，空间O（1）），
或映射或hash（时间O（n），空间O（n））。时间或空间，必须牺牲一个，自个权衡吧。 
综上，若是数组有序的情况下，优先考虑两个指针两端扫描法，以达到最佳的时（O（N）），空（O（1））效应。否则，如果要排序的话，时间复杂度最快当然是只能达到N*logN，
空间O（1）则是不在话下。 
*/

#include <iostream>
#include <stdio.h>
#include <algorithm>
//#include <vector>
using namespace std;


//两个指针扫描法
pair<int,int> findNumber(int* s,int n,int x)
{
	
	//sort(s,s+n);  数组无序先排序

	int * begin = s;
	int * end = s + n-1;
	while(begin < end)
	{
		if(*begin + *end > x)
		{
			--end;//尾指针减1
		}else if(*begin + *end < x)
		{
			++begin;//头指针加1
		}else 
		{
			return pair<int,int>(*begin,*end);
		}
	}
   return pair<int,int>(-1,-1);
}

//另一种实现方法
bool  findnum2(int data[],unsigned int length, int sum, int& first_num, int& second_num)
{
	if(length<1)
	{
		return false;
	}
	int begin = 0;
	int end = length - 1;
	while(end > begin)
	{
		long current_sum = data[begin] + data[end];
		if(current_sum == sum)
		{
			first_num = data[begin];
			second_num = data[end];
			return true;
		}
		//当前值大于最大的和，排序的数组中要把尾端的指针减少
		else if(current_sum > sum)
			end--;
		else
			begin++;
	}
	return false; 
}
int main() 
{
	//pair<int,int> p;
	int arr[]={1,2,4,7,11,15};
	int m=1,n=2;
	int &i=m;
	int &j=n;
	//p=findNumber(arr,6,15);
	//cout<<p.first<<" "<<p.second<<endl;
	cout<< findnum2(arr,6,15,i,j)<<endl;
	getchar();
	return 0;
}
